package com.lan.util;


import com.lan.antlr.ScriptParser;
import com.lan.model.Type;
import com.lan.model.Variable;
import com.lan.ot.ClazzOt;
import com.lan.ot.Value;
import com.lan.script.NullOt;
import org.apache.commons.collections.CollectionUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class Utils {

    ///////////////////////////////////////////////////////////
    //内置函数


    ///////////////////////////////////////////////////////////
    /// 各种运算
    public static Object add(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() + ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() + ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() + ((Number) o2).doubleValue();
        } else if (TypeUtils.isString(o1) || TypeUtils.isString(o2)) {
            String l;
            if (TypeUtils.isString(o1)) {
                l = (String) o1;
            } else {
                l = o1.toString();
            }

            String r;
            if (TypeUtils.isString(o2)) {
                r = (String) o2;
            } else {
                r = o2.toString();
            }

            return l + r;
        }
        return null;
    }


    public static Object sub(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() - ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() - ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() - ((Number) o2).doubleValue();
        }
        return null;
    }

    public static Object mul(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() * ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() * ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() * ((Number) o2).doubleValue();
        }
        return null;
    }

    public static Object div(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() / ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() / ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() / ((Number) o2).doubleValue();
        }
        return null;
    }

    public static Object mod(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() % ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() % ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() % ((Number) o2).doubleValue();
        }
        return null;
    }


    public static Boolean EQ(Object o1, Object o2) {
        if (o1 instanceof NullOt || o2 instanceof NullOt) {
            if (o1 instanceof NullOt && o2 instanceof NullOt) {
                return true;
            }
            if (o1 instanceof NullOt) {
                if (o2 == null) {
                    return true;
                }
                return false;
            } else if (o2 instanceof NullOt) {
                if (o1 == null) {
                    return true;
                }
                return false;
            }
        }


        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() == ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() == ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() == ((Number) o2).doubleValue();
        } else if (o1 instanceof String && o2 instanceof String) {
            return ((String) o1).equals(((String) o2));
        }
        return null;
    }


    public static Boolean NotEq(Object o1, Object o2) {
        if (o1 instanceof NullOt || o2 instanceof NullOt) {
            if (o1 instanceof NullOt && o2 instanceof NullOt) {
                return true;
            }
            if (o1 instanceof NullOt) {
                if (o2 != null) {
                    return true;
                }
                return false;
            } else if (o2 instanceof NullOt) {
                if (o1 != null) {
                    return true;
                }
                return false;
            }
        }

        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() != ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() != ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() != ((Number) o2).doubleValue();
        }
        return null;
    }

    public static Object GE(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() >= ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() >= ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() >= ((Number) o2).doubleValue();
        }
        return null;
    }

    public static Object GT(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() > ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() > ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() > ((Number) o2).doubleValue();
        }
        return null;
    }

    public static Object LE(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() <= ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() <= ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() <= ((Number) o2).doubleValue();
        }
        return null;
    }

    public static Object LT(Object o1, Object o2) {
        if (TypeUtils.isInteger(o1) && TypeUtils.isInteger(o2)) {
            return ((Number) o1).intValue() < ((Number) o2).intValue();
        } else if (TypeUtils.isLong(o1) && TypeUtils.isLong(o2)) {
            return ((Number) o1).longValue() < ((Number) o2).longValue();
        } else if (TypeUtils.isDouble(o1) && TypeUtils.isDouble(o2)) {
            return ((Number) o1).doubleValue() < ((Number) o2).doubleValue();
        }
        return null;
    }


    public static Object INC(Object value) {
        if (TypeUtils.isInteger(value)) {
            return ((Integer) value).intValue() + 1;
        } else if (TypeUtils.isLong(value)) {
            return ((Long) value).longValue() + 1;
        } else if (TypeUtils.isDouble(value)) {
            return ((Double) value).doubleValue() + 1;
        }
        return null;

    }

    public static Object DEC(Object value) {
        if (TypeUtils.isInteger(value)) {
            return ((Integer) value).intValue() - 1;
        } else if (TypeUtils.isLong(value)) {
            return ((Long) value).longValue() - 1;
        } else if (TypeUtils.isDouble(value)) {
            return ((Double) value).doubleValue() - 1;
        }
        return null;
    }


    public static Variable getValue(Object object) {
        if (object == null) {
            return null;
        }
        if (object instanceof Value) {
            Value v = ((Value) object);
            Object o = v.getValue();
            if (o instanceof Value) {
                return getValue(o);
            }
            return new Variable(v.getVariable().getType(), o);
        } else if (object instanceof Variable) {
            return (Variable) object;
        }
        return new Variable(Type.Integer, object);
    }


    public static Object visitLiteral(ScriptParser.LiteralContext ctx) {
        Object rtn = null;
        if (ctx.INTEGER_LITERAL() != null) {
            rtn = Integer.valueOf(ctx.INTEGER_LITERAL().getText());
            rtn = new Variable(Type.Integer, rtn);
        } else if (ctx.STRING_LITERAL() != null) {
            Variable variable = new Variable(Type.String);
            String v = ctx.STRING_LITERAL().getText();
            variable.setValue(v.substring(1, v.length() - 1));
            rtn = variable;
        } else if (ctx.FLOAT_LITERAL() != null) {
            rtn = Double.valueOf(ctx.FLOAT_LITERAL().getText());
            rtn = new Variable(Type.Float, rtn);
        } else if (ctx.BOOL_LITERAL() != null) {
            if ("true".equalsIgnoreCase(ctx.BOOL_LITERAL().getText())) {
                rtn = Boolean.TRUE;
            } else {
                rtn = Boolean.FALSE;
            }
            rtn = new Variable(Type.Boolean, rtn);
        } else if (ctx.NULL_LITERAL() != null) {
            rtn = NullOt.instance();
        }
        return rtn;
    }


    public static void getAssign(Object left, Object right) {
        Value value = (Value) left;
        if (right instanceof Value) {
            Value rv = (Value) right;
            if (value.getValue() instanceof ClazzOt) {
                ClazzOt ot = (ClazzOt) value.getValue();
                ot.setValue(value.getVariable(), rv.getValue());
            } else {
                value.setValue(rv.getValue());
            }
            value.getVariable().setType(rv.getVariable().getType());
        } else if (right instanceof Variable) {
            Variable variable = (Variable) right;
            if (value.getValue() instanceof ClazzOt) {
                ClazzOt ot = (ClazzOt) value.getValue();
                ot.setValue(value.getVariable(), variable.getValue());
            } else {
                value.setValue(variable.getValue());
            }
            value.getVariable().setType(variable.getType());
        } else {
            value.setValue(right);
        }
    }

//
//    public static Object getClazzOtData(ClazzOt ot) {
//        Object data = ot.getData();
//        Map<String, Variable> kvMap = ot.getKeyVariable();
//        if (kvMap == null) {
//            return data;
//        }
//
//        for (Map.Entry<String, Variable> entry : kvMap.entrySet()) {
//
//        }
//
//        return data;
//    }


    public static Object getOpt(ScriptParser.ExpressionContext ctx, Object left, Object right) {
        Object rtn = null;
        switch (ctx.bop.getType()) {
            case ScriptParser.ADD:
                Variable leftObject = Utils.getValue(left);
                Variable rightObject = Utils.getValue(right);
                rtn = Utils.add(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.SUB:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.sub(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.MUL:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.mul(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.DIV:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.div(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.MOD:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.mod(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.EQUAL:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                if (leftObject == null && rightObject != null) {
                    rtn = false;
                } else if (leftObject != null && rightObject == null) {
                    rtn = false;
                } else {
                    rtn = Utils.EQ(leftObject.getValue(), rightObject.getValue());
                }
                break;
            case ScriptParser.NOTEQUAL:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                if (leftObject == null && rightObject != null) {
                    rtn = false;
                } else if (leftObject != null && rightObject == null) {
                    rtn = false;
                } else {
                    rtn = Utils.NotEq(leftObject.getValue(), rightObject.getValue());
                }
                break;
            case ScriptParser.LE:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.LE(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.LT:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.LT(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.GT:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.GT(leftObject.getValue(), rightObject.getValue());
                break;
            case ScriptParser.AND:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = (Boolean) leftObject.getValue() && (Boolean) rightObject.getValue();
                break;
            case ScriptParser.OR:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = (Boolean) leftObject.getValue() || (Boolean) rightObject.getValue();
                break;
            case ScriptParser.ASSIGN:
                rightObject = Utils.getValue(right);
                if (left instanceof Value) {
                    ((Value) left).setValue(rightObject.getValue());
                    rtn = right;
                } else {
                    System.out.println("Unsupported feature during assignment");
                }
                break;
            case ScriptParser.ADD_ASSIGN:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.add(leftObject.getValue(), rightObject.getValue());
                if (left instanceof Value) {
                    Value v = (Value) left;
                    v.setValue(rtn);
                    rtn = v;
                } else if (left instanceof Variable) {
                    Variable v = (Variable) left;
                    v.setValue(rtn);
                    rtn = v;
                }
                break;
            case ScriptParser.SUB_ASSIGN:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.sub(leftObject.getValue(), rightObject.getValue());
                if (left instanceof Value) {
                    Value v = (Value) left;
                    v.setValue(rtn);
                    rtn = v;
                } else if (left instanceof Variable) {
                    Variable v = (Variable) left;
                    v.setValue(rtn);
                    rtn = v;
                }
                break;
            case ScriptParser.MUL_ASSIGN:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.mul(leftObject.getValue(), rightObject.getValue());
                if (left instanceof Value) {
                    Value v = (Value) left;
                    v.setValue(rtn);
                    rtn = v;
                } else if (left instanceof Variable) {
                    Variable v = (Variable) left;
                    v.setValue(rtn);
                    rtn = v;
                }
                break;
            case ScriptParser.DIV_ASSIGN:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.div(leftObject.getValue(), rightObject.getValue());
                if (left instanceof Value) {
                    Value v = (Value) left;
                    v.setValue(rtn);
                    rtn = v;
                } else if (left instanceof Variable) {
                    Variable v = (Variable) left;
                    v.setValue(rtn);
                    rtn = v;
                }
                break;
            case ScriptParser.MOD_ASSIGN:
                leftObject = Utils.getValue(left);
                rightObject = Utils.getValue(right);
                rtn = Utils.mod(leftObject.getValue(), rightObject.getValue());
                if (left instanceof Value) {
                    Value v = (Value) left;
                    v.setValue(rtn);
                    rtn = v;
                } else if (left instanceof Variable) {
                    Variable v = (Variable) left;
                    v.setValue(rtn);
                    rtn = v;
                }
                break;
            default:
                break;
        }
        return rtn;
    }


    public static void main(String[] args) {
        String str = "\"xxxxx\"";
        System.out.println(str.substring(1, str.length() - 1));
    }

}
